/*
 * PhotonRTOS础光实时操作系统 -- task测试
 *
 * Copyright (C) 2023 国科础石(重庆)软件有限公司
 *
 * 作者: Zicheng Hu <huzicheng@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#include "../utest.h"
#include "../ioc.h"
#include <Os.h>

#define IdUnitTestTask 0
#define IdTestTask1 1
#define IdTestTask2 2
#define IdIocTask 3

static volatile int32_t task1_exit_flags;

TASK(TestTask1, app0)
{
	VAR(TaskType, AUTOMATIC) tid;
	VAR(StatusType, AUTOMATIC) st;

	/* 任务成功激活 */
	st = GetTaskID(&tid);
	ASSERT_EQ(st, E_OK);
	ASSERT_EQ(tid, IdTestTask1);

	LOGI("osek task[%d]: running...", tid);

	task1_exit_flags = 1;
	LOGI("osek task[%d]: end...", tid);

	/* 终止当前任务 */
	TerminateTask();
	/* 任务终止后不允许到这里 */
	ASSERT_FALSE(1);
}

TASK(TestTask2, app1)
{
	VAR(TaskType, AUTOMATIC) tid;
	VAR(StatusType, AUTOMATIC) st;

	/* 任务成功激活 */
	st = GetTaskID(&tid);
	ASSERT_EQ(st, E_OK);
	ASSERT_EQ(tid, IdTestTask2);

	LOGI("osek task[%d]: running...\n", tid);

	WaitEvent(0x4);

	LOGI("osek task[%d]: get event 4...\n", tid);
	LOGI("osek task[%d]: end...", tid);

	/* 终止当前任务 */
	TerminateTask();
	/* 任务终止后不允许到这里 */
	ASSERT_FALSE(1);
}

#ifdef CONFIG_IOC
TASK(UnitIocTask, app1)
{
	VAR(TaskType, AUTOMATIC) tid;
	VAR(StatusType, AUTOMATIC) st;
	Std_ReturnType ret = IOC_E_OK;

	int a = 0;
	int b = 0;
	int c = 0;

	int abak = 0;
	int bbak = 1;
	int cbak = 3;
	int count = 0;
	int PrintkCount = 0;
	/* 任务成功激活 */
	st = GetTaskID(&tid);
	ASSERT_EQ(st, E_OK);
	ASSERT_EQ(tid, IdIocTask);

	LOGI("core %d 通知对端核心测试开始", GetCoreID());
	a = IOCTESTSTART;
	ret = IocWrite_CORE1_TO_CORE0(&a, sizeof(a), &b, sizeof(b), &c, sizeof(c));
	ASSERT_EQ(ret, IOC_E_OK);

	LOGI("等待对方核心应答");
	while (IOC_E_OK != IocRead_CORE0_TO_CORE1(&a, sizeof(a), &b, sizeof(b), &c, sizeof(c))) {
		if (count == 0) {
			LOGI("error cpu0未发送就绪信号");
		}
		count++;
		count = count % 50000;
	}
	if (a != IOCTESTSTART) {
		LOGI("a = %d", a);
	}
	ASSERT_EQ(a, IOCTESTSTART);

	LOGI("core %d IocRead_CORE0_TO_CORE1 测试开始", GetCoreID());
	while(1) {
		ret = IocRead_CORE0_TO_CORE1(&a, sizeof(a), &b, sizeof(b), &c, sizeof(c));
		if (IOC_E_OK == ret) {
			if (a == IOCTESTEND) {
				break;
			}
			ASSERT_EQ(b, a+1);
			ASSERT_EQ(c, a+3);
		} else if (IOC_E_NO_DATA != ret) {
			LOGI("a %d b %d c %d\n", a, b, c);
		} else {
			PrintkCount++;
			PrintkCount = PrintkCount % 10000;
			if (PrintkCount == 0) {
				LOGI("a %d b %d c %d ret %d\n", a, b, c, ret);
			}
		}
	}
	LOGI("core %d IocRead_CORE0_TO_CORE1 测试结束", GetCoreID());
	LOGI("core %d IocRec_QUEUE_CORE0_TO_CORE1 测试开始", GetCoreID());
	while(1) {
		a = 0;
		b = 0;
		c = 0;
		ret = IocRec_QUEUE_CORE0_TO_CORE1(&a, sizeof(a), &b, sizeof(b), &c, sizeof(c));
		if (a == IOCTESTEND) {
			break;
		}
		switch (ret)
		{
		case IOC_E_LOST_DATA:
		case IOC_E_OK:
			ASSERT_EQ(a, abak);
			ASSERT_EQ(b, bbak);
			ASSERT_EQ(c, cbak);
			abak++;
			bbak = abak+1;
			cbak = abak+3;
			if (abak == 500) {
				abak = 0;
				bbak = 1;
				cbak = 3;
			}
			break;
		case IOC_E_NO_DATA:break;
		default:
			LOGI("IocRec_QUEUE_CORE0_TO_CORE1 %d\n", ret);
			ASSERT_TRUE(0);
			break;
		}
	}

	LOGI("core %d 通知对端核心测试结束", GetCoreID());
	a = IOCTESTEND;
	ret = IocWrite_CORE1_TO_CORE0(&a, sizeof(a), &b, sizeof(b), &c, sizeof(c));
	ASSERT_EQ(ret, IOC_E_OK);
	TerminateTask();
}
#endif

TEST(ActivateTask)
{
	VAR(StatusType, AUTOMATIC) st;

	/* 测试激活无效的任务 */
	st = ActivateTask(OS_NR_TASK - 1);
	ASSERT_NE(st, E_OK);
	st = ActivateTask(IdTestTask1);
	ASSERT_EQ(st, E_OK);
	/* 等待子任务退出 */
	while (!task1_exit_flags)
		Schedule();
}

TEST(ChainTask)
{
	VAR(StatusType, AUTOMATIC) st;

	/* 测试激活无效的任务 */
	st = ChainTask(OS_NR_TASK);
	ASSERT_EQ(st, E_OS_ID);
}

TEST(GetTaskID)
{
	VAR(TaskType, AUTOMATIC) tid;
	VAR(StatusType, AUTOMATIC) st;

	st = GetTaskID(&tid);
	ASSERT_EQ(st, E_OK);
	ASSERT_EQ(tid, IdUnitTestTask);
}

TEST(GetTaskState)
{
	VAR(StatusType, AUTOMATIC) st;
	VAR(TaskStateType, AUTOMATIC) state;

	st = GetTaskState(IdUnitTestTask, &state);
	ASSERT_EQ(st, E_OK);
	ASSERT_EQ(state, RUNNING);

	st = GetTaskState(IdTestTask1, &state);
	ASSERT_EQ(st, E_OK);
	ASSERT_NE(state, RUNNING);
}

TEST(ControlIdle)
{
	StatusType st;

#if defined(EXTENDED_STATUS)

	/**
	 * [SWS_Os_00771] ⌈如果参数CoreID或IdleMode无效（例如引用的核心不存在；空闲模式未知） ，函数ControlIdle应返回E_OS_ID 。在单核系统中，CoreID 的检查将被省略。 ⌋ ( SRS_Os_80023 )
	 */
	st = ControlIdle(OsNumberOfCores, IDLE_NO_HALT);
	ASSERT_EQ(st, E_OS_ID);
#endif

	/**
	 * [SWS_Os_00770] ⌈如果未检测到错误且参数有效，则ControlIdle函数应返回E_OK ⌋ ( SRS_Os_80023 )
	 */
	st = ControlIdle(0, IDLE_NO_HALT);
	ASSERT_EQ(st, E_OK);

	/**
	 * [ SWS_Os_00802 ]⌈ 如果核心（由CoreID给出）已经处于另一个空闲模式（与给定的 IdleMode 不同），则新的IdleMode将在下一次核心进入空闲模式时生效。⌋ (SRS_Os_80023)
	 */


}

#if defined(AUTOSAR_OS_APPLICATION)
TEST(ActivateTaskAsyn)
{
	/**
	 * [SWS_Os_00818] ⌈ ActivateTaskAsyn()的可用性：在支持 OS 应用程序的系统中可用。 ⌋ (SRS_Os_80015)
	 * 注意：如果在任务激活期间发生错误，并且调用者已经离开（例如调用者 OS-Application 已经终止，或者调用者核心正在关闭，或者...）对错误钩子的调用将被丢弃并且不进行报告。
	 */
	ActivateTaskAsyn(IdTestTask2);
}
#endif /* defined(AUTOSAR_OS_APPLICATION) */

TEST_SUIT(Task)
{
	UTEST_CASE(ActivateTask);
	UTEST_CASE(ChainTask);
	UTEST_CASE(GetTaskID);
	UTEST_CASE(GetTaskState);
	UTEST_CASE(ControlIdle);
#if ((OsNumberOfCores > 1) && defined(AUTOSAR_OS_APPLICATION))
	UTEST_CASE(ActivateTaskAsyn);
#endif /* ((OsNumberOfCores > 1) && defined(AUTOSAR_OS_APPLICATION)) */
}
